import matchmove, supersampler, transform, disk, sphere, cube
import numpy

from PIL import Image
# Get the Python Qt bindings (PyQt4 or PySide)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# Also get the bridge from Qt to OpenGL
from PyQt4.QtOpenGL import *
# OpenGL itself of course
import OpenGL
from OpenGL.GL import *
# Need numpy for data arrays
from numpy import array, dot, zeros, multiply, ones
from math import sin
# need some basic math
import math
# And basic operating system stuff (to quit)
import sys
from OpenGL.raw.GLUT import glutSolidTeapot, glutSolidCube, glutPostRedisplay,\
    glutSetWindow
from OpenGL.GL.EXT.framebuffer_object import glGenFramebuffersEXT,\
    glGenRenderbuffersEXT
from OpenGL.raw.GL.ARB.framebuffer_object import glGenFramebuffers
from OpenGL.raw.GL.EXT.framebuffer_object import glBindFramebufferEXT,\
    glBindRenderbufferEXT, glRenderbufferStorageEXT
from OpenGL.raw.GL.constants import GL_TEXTURE_2D
from OpenGL.GLUT.special import glutDisplayFunc
windowHeight = 360
windowWidth = 640
OUTPUT = 0
SUPERSAMPLE = 1
LIGHTPOV = 2
DEPTHLIGHT = 3
CAMERAPOV = 4
DEPTHCAMERA = 5

# Camera constants / Matchmove
X_LIST = [
    array([0.,  0.,   0., 1], dtype="float32"),
    array([0.,  165., 0., 1], dtype="float32"),
    array([80., 165., 0., 1], dtype="float32"),
    array([80., 0.,   0., 1.],dtype="float32")]

    # NDC for each marker
P_LIST = [ 
    array([-0.925, -0.75555556], dtype="float32"),
    array([-0.284375, 0.05], dtype="float32"),
    array([0.353125, 0.01666667], dtype="float32"),
    array([0.934375, -0.8], dtype="float32")]

FOVY = 0.481461315611442
ASPECT = 1.504
Z_NEAR = 37.2
Z_FAR = 600 
PERSPECTIVE_TRANSFORM = transform.perspective(FOVY, ASPECT, Z_NEAR, Z_FAR)        
CAMERA_TRANSFORM = matchmove.solve(PERSPECTIVE_TRANSFORM, P_LIST, X_LIST )
PMV_TRANSFORM = transform.compose(PERSPECTIVE_TRANSFORM, CAMERA_TRANSFORM)

frame = 1
frameSaved = -1


save = False


LIGHT_TRANS = transform.translate([-12, -171, 100])
LIGHT_ROT = transform.rotate_x(math.pi/2.0)
#########################################################################
# vertex shader
vshader_src = """
    #version 110

    uniform mat4 cameraMvTransform;
    uniform mat4 cameraPmvTransform;
    uniform mat4 lightMvTransform;
    uniform mat4 lightPmvTransform;
    varying vec3 worldSpacePosition;
    varying vec3 worldSpaceNormal;    
    
    void main()
    {
        gl_Position = cameraPmvTransform * gl_Vertex;
        worldSpacePosition = gl_Vertex.xyz;
        worldSpaceNormal = gl_Normal.xyz;
    }
    """

vshadow_map_shader_src = """
    #version 110

    uniform mat4 lightMvTransform;
    uniform mat4 lightPmvTransform;
    varying vec3 worldSpacePosition;
    varying vec3 worldSpaceNormal;            

    void main()
    {
        gl_Position = lightPmvTransform * gl_Vertex;
        worldSpacePosition = gl_Vertex.xyz;
        worldSpaceNormal = gl_Normal.xyz;
    }
    """
    
# fragment shader
fshader_src = """
    #version 110
    
    uniform mat4 lightPmvTransform;
    uniform mat4 biasMatrix;
    uniform vec3 lightPosition;
    uniform vec4 diffuse;
    uniform vec4 ambient;
    uniform vec4 specular;    
    uniform sampler2DShadow shadowMap;
    varying vec3 worldSpacePosition;
    varying vec3 worldSpaceNormal;
    
    uniform float shiny;
    void main()
    {
        vec3 N = normalize(worldSpaceNormal);
        vec3 L = normalize(lightPosition - worldSpacePosition);   
        vec3 E = normalize(worldSpacePosition); 
        vec3 R = normalize(-reflect(L,N)); 
          
        vec4 Idiff = diffuse * max(dot(N,L), 0.0);  
        Idiff = clamp(Idiff, 0.0, 1.0); 
        
        vec4 Ispec = specular * pow(max(dot(R,E),0.0),0.3*shiny);
        Ispec = clamp(Ispec, 0.0, 1.0); 

        /* transform worldSpacePosition to light space coordinates */
        vec4 wsPos = vec4(worldSpacePosition, 1.0);
        vec4 lsCoords = lightPmvTransform * wsPos;
        lsCoords = biasMatrix * lsCoords;

        // figure out the z-buffer
        vec4 shadowComponent = shadow2DProj(shadowMap, lsCoords);
       
        gl_FragColor = shadowComponent * (Ispec + Idiff) + ambient;
    }
    """

fshadow_map_shader_src = """
    #version 110

    uniform vec3 lightPosition;
    uniform vec4 diffuse;
    uniform vec4 ambient;
    uniform vec4 specular;
    varying vec3 worldSpacePosition;
    varying vec3 worldSpaceNormal;

    uniform float shiny;
    void main()
    {
        vec3 N = normalize(worldSpaceNormal);
        vec3 L = normalize(lightPosition - worldSpacePosition);
        vec3 E = normalize(worldSpacePosition);
        vec3 R = normalize(-reflect(L,N));

        vec4 Idiff = diffuse * max(dot(N,L), 0.0);
        Idiff = clamp(Idiff, 0.0, 1.0);
        
        vec4 Ispec = specular * pow(max(dot(R,E), 0.0), 0.3 * shiny);
        Ispec = clamp(Ispec, 0.0, 1.0);

        gl_FragColor = Idiff + Ispec + ambient; 
    }
    """

#########################################################################

edge = array([0, 1,2,3], dtype='uint32')
#'''
vertex = array([80, 0, -165, 1,
0, 0, -165, 1,
0, 0, 0, 1,
80, 0, 0, 1], dtype='float32')

bias = array([ 0.5, 0.0, 0.0, 0.0,
            0.0, 0.5, 0.0, 0.0,
            0.0, 0.0, 0.5, 0.0,
            0.5, 0.5, 0.5, 1.0], dtype="float32")

# Basic GL window to play with
class MyGL(QGLWidget):
    def __init__(self, parent, windowType):
        QGLWidget.__init__(self, parent)
        self.source = None
        self.destination = None
        self.pixels = None
        self.doneFront = False
        self.doneBack = False
        self.windowType = windowType
        self.depths = None
        self.framePrevious = -1
        self.passes = 0
        
        # set up the perspective transform we will ALWAYS use        
        self.image = Image.open("data/table.png").transpose(Image.FLIP_TOP_BOTTOM)        

    def sizeLimit(self, width, height):
        self.setMinimumSize(QSize(width,height))
        self.setMaximumSize(QSize(width,height))
        self.width = width
        self.height = height
               
    def initializeGL(self):
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glClearDepth(1)
        
        # set up regular shaders
        vshader_id = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(vshader_id, vshader_src)
        glCompileShader(vshader_id)
        print("vertex shader compile status: "+
                str(glGetShaderiv(vshader_id, GL_COMPILE_STATUS)))
        print(glGetShaderInfoLog(vshader_id))

        fshader_id = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(fshader_id, fshader_src)
        glCompileShader(fshader_id)
        print("fragment shader compile status: "+
                str(glGetShaderiv(fshader_id, GL_COMPILE_STATUS)))
        print(glGetShaderInfoLog(fshader_id))
        
        self.shader = glCreateProgram()
        glAttachShader(self.shader, vshader_id)
        glAttachShader(self.shader, fshader_id)
        glLinkProgram(self.shader)
        print("shader program link status: "+
                str(glGetProgramiv(self.shader, GL_LINK_STATUS)))
        if glGetProgramiv(self.shader, GL_LINK_STATUS) == 0:
            sys.exit()
        
        # set up shaders for generating shadow map
        vshadow_map_shader_id = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(vshadow_map_shader_id, vshadow_map_shader_src)
        glCompileShader(vshadow_map_shader_id)
        print("vertex shadow map shader compile status: "+
                str(glGetShaderiv(vshadow_map_shader_id, GL_COMPILE_STATUS)))
        print(glGetShaderInfoLog(vshadow_map_shader_id))
    
        fshadow_map_shader_id = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(fshadow_map_shader_id, fshadow_map_shader_src)
        glCompileShader(fshadow_map_shader_id)
        print("fragement shadow map shader compile status: "+
                str(glGetShaderiv(fshadow_map_shader_id, GL_COMPILE_STATUS)))
        print(glGetShaderInfoLog(fshadow_map_shader_id))

        self.shadow_map_shader = glCreateProgram()
        glAttachShader(self.shadow_map_shader, vshadow_map_shader_id)
        glAttachShader(self.shadow_map_shader, fshadow_map_shader_id)
        glLinkProgram(self.shadow_map_shader)
        print("shadow map shader program link status: "+
                str(glGetProgramiv(self.shadow_map_shader, GL_LINK_STATUS)))
        if glGetProgramiv(self.shader, GL_LINK_STATUS) == 0:
            sys.exit()
            
        self.meshbuffers = glGenBuffers(8)
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[0])
        glBufferData(GL_ARRAY_BUFFER, vertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[1])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, edge, GL_STATIC_DRAW)
        x = 40
        y = 15
        z = -80
        [self.diskVertex,self.diskEdge]=disk.vertexAndEdge(30, x, y, z, 16)

        
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[2])
        glBufferData(GL_ARRAY_BUFFER, self.diskVertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[3])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.diskEdge, GL_STATIC_DRAW)
        
        [self.sphereVertex,self.sphereEdge]=sphere.vertexAndEdge(10, x, y, z, 16)
        
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[4])
        glBufferData(GL_ARRAY_BUFFER, self.sphereVertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[5])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.sphereEdge, GL_STATIC_DRAW)
        
        [self.cubeVertex, self.cubeEdge] = cube.vertexAndEdge(x-30, y-10, z-40, 10, 10, 10)       
        
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[6])
        glBufferData(GL_ARRAY_BUFFER, self.cubeVertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[7])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.cubeEdge, GL_STATIC_DRAW)
        
        self.lightPosition = glGetUniformLocation(self.shader, "lightPosition")
        self.diffuseValues = glGetUniformLocation(self.shader, "diffuse")
        self.ambientValues = glGetUniformLocation(self.shader, "ambient")
        self.specularValues = glGetUniformLocation(self.shader, "specular")
        self.shinyValue = glGetUniformLocation(self.shader, "shiny")
        self.lightPositionShadowMap = glGetUniformLocation(self.shadow_map_shader, "lightPosition")
        self.diffuseValuesShadowMap = glGetUniformLocation(self.shadow_map_shader, "diffuse")
        self.ambientValuesShadowMap = glGetUniformLocation(self.shadow_map_shader, "ambient")
        self.specularValuesShadowMap = glGetUniformLocation(self.shadow_map_shader, "specular")
        self.shinyValueShadowMap = glGetUniformLocation(self.shadow_map_shader, "shiny")
        self.cameraMvLocation = glGetUniformLocation(self.shader, "cameraMvTransform")
        self.cameraPmvLocation = glGetUniformLocation(self.shader, "cameraPmvTransform")
        self.lightMvLocation = glGetUniformLocation(self.shader, "lightMvTransform")
        self.lightPmvLocation = glGetUniformLocation(self.shader, "lightPmvTransform")
        self.lightMvLocationShadowMap = glGetUniformLocation(self.shadow_map_shader, "lightMvTransform")
        self.lightPmvLocationShadowMap = glGetUniformLocation(self.shadow_map_shader, "lightPmvTransform")
        self.shadowMapLocation = glGetUniformLocation(self.shader, "shadowMap")
        self.biasLocation = glGetUniformLocation(self.shader, "biasMatrix")
        
    def resizeGL(self, w, h):
        glViewport(0, 0, w, h) 
    
    def paintGL(self):
        global frameSaved
        global frame
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glEnable(GL_TEXTURE_2D)
        glEnable(GL_DEPTH_TEST)
        
        if (self.windowType == LIGHTPOV):            
            # first generate a shadow map by rendering from the light's perspective
            lightMvTransform = transform.compose(LIGHT_ROT, LIGHT_TRANS)
            lightPmvTransform = transform.compose(PERSPECTIVE_TRANSFORM, lightMvTransform)
            
            glUseProgram(self.shadow_map_shader)
            glUniformMatrix4fv(self.lightMvLocationShadowMap, 1, True, lightMvTransform.flatten())
            glUniformMatrix4fv(self.lightPmvLocationShadowMap, 1, True, lightPmvTransform.flatten())
            
            glUniform3f(self.lightPositionShadowMap, 12,171,100)
            glUniform4f(self.diffuseValuesShadowMap, 0.5,0.5,0.5,1)
            glUniform4f(self.ambientValuesShadowMap, 182/255.,107/255.,20/255.,1)
            glUniform4f(self.specularValuesShadowMap, 0.01,0.01,0.01,1)
            glUniform1f(self.shinyValueShadowMap, 1)
            
            self.drawTable()
            self.setupObjects()
            self.drawCube()
            self.drawDisk()
            self.drawSphere()          
            
            self.pixels = glReadPixels( 0,0, self.width, self.height, GL_RGBA, GL_FLOAT)
            self.depths = glReadPixels( 0,0, self.width, self.height, GL_DEPTH_COMPONENT, GL_FLOAT)                
                            
        elif(self.windowType == DEPTHLIGHT):
            depths = self.source.getDepths()
            if depths is not None:
                render = ones((len(depths), len(depths[0]), 3))
                for x in range(len(depths)):
                    for y in range(len(depths[x])):
                        value = depths[x][y]
                        render[x][y][0]= value
                        render[x][y][1]= value
                        render[x][y][2]= value
                    
                glDrawPixels(self.width, self.height,GL_RGB, GL_FLOAT, render)
                
        elif(self.windowType == CAMERAPOV): 
            if(frame == frameSaved):
                frame += 1
                print "Render:" + str(frame)

            cameraPmvTransform = transform.compose(PERSPECTIVE_TRANSFORM, PMV_TRANSFORM)
            
            lightMvTransform = transform.compose(LIGHT_ROT, LIGHT_TRANS)
            lightPmvTransform = transform.compose(PERSPECTIVE_TRANSFORM, lightMvTransform)
            
            glUseProgram(self.shader)
            glUniformMatrix4fv(self.cameraMvLocation, 1, True, CAMERA_TRANSFORM.flatten())
            glUniformMatrix4fv(self.cameraPmvLocation, 1, True, PMV_TRANSFORM.flatten())
            glUniformMatrix4fv(self.lightMvLocation, 1, True, lightMvTransform.flatten())
            glUniformMatrix4fv(self.lightPmvLocation, 1, True, lightPmvTransform.flatten())           
            glUniform3f(self.lightPosition, 12,171,100)
            glUniform4f(self.diffuseValues, 0.5,0.5,0.5,1)
            glUniform4f(self.ambientValues, 182/255.,107/255.,20/255.,1)
            glUniform4f(self.specularValues, 0.01,0.01,0.01,1)
            glUniform1f(self.shinyValue, 1)
            
            depths = self.source.getDepths()
            if depths is not None:
                # generate a texture for the shadow map                
                shadowMapTexture = glGenTextures(1)
                glBindTexture(GL_TEXTURE_2D, shadowMapTexture)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL)
                glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, self.width, self.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, array(depths))
                glUniform1i(self.shadowMapLocation,0)
                glUniformMatrix4fv(self.biasLocation, 1, True, bias)


                self.drawTable()
                self.setupObjects()
                self.drawCube()
                self.drawDisk()
                self.drawSphere()
                
                self.pixels = glReadPixels( 0,0, self.width, self.height, GL_RGBA, GL_FLOAT)
                self.depths = glReadPixels( 0,0, self.width, self.height, GL_DEPTH_COMPONENT, GL_FLOAT)
                
                self.destination.redraw()
        elif(self.windowType == DEPTHCAMERA):
            depths = self.source.getDepths()
            if depths is not None:
                render = ones((len(depths), len(depths[0]), 3))
                for x in range(len(depths)):
                    for y in range(len(depths[x])):
                        value = depths[x][y]
                        render[x][y][0]= value
                        render[x][y][1]= value
                        render[x][y][2]= value
                
                glDrawPixels(self.width, self.height,GL_RGB, GL_FLOAT, render)
        elif(self.windowType == OUTPUT):
                        
            foreground = self.source.getPixels()
            
            background = array(list(self.image.getdata()))
            (bgWidth, bgHeight) = background.shape 
          
            background = (1/255.) * background
            
            # add an alpha value of 1 to every pixel in background                      
            alphas = ones((bgWidth,1), dtype='float32')        
            background_rgba = numpy.append(background, alphas, 1)  
              
            background_rgba = numpy.reshape(background_rgba, (windowHeight, windowWidth,4))         
            
            foreground = numpy.reshape(foreground ,(self.height, self.width,4))
            
            sizeRatioW = float(len(foreground))/float(len(background_rgba))

            for i in range(len(foreground)):
                for j in range(len(foreground[0])):
                    if foreground[i][j][3] == 0:
                        foreground[i][j] = background_rgba[i/sizeRatioW][j/sizeRatioW]
                        
                        
            glDrawPixels(self.width, self.height, GL_RGBA, GL_FLOAT, foreground)
            self.pixels = glReadPixels( 0,0, self.width, self.height, GL_RGBA, GL_FLOAT)
            print self.passes
            self.passes += 1
            if self.passes >= 2:
                self.done = True
            if(frameSaved < frame and save):           
                visibleImage = self.grabFrameBuffer(True)
                fileNameFormat = str(QDir.currentPath()) + "/animation/" + "brandonYuhStuartRowe%03d.png"
                fileName = fileNameFormat % frame
                try:
                    visibleImage.save(fileName)                    
                    frameSaved = frame
                    print "Saving:" + str(frame)
                    self.source.setFocus()

                    self.source.redraw()
                finally:
                    pass
                
            
        elif(self.windowType == SUPERSAMPLE):
            
            if(self.source.passes >=2):
                outW = self.width
                outH = self.height
                foreground = self.source.getPixels()
                inW = self.source.width
                inH = self.source.height
                result = supersampler.supersample(foreground, inW, inH, outW, outH, supersampler.GRID)
                glDrawPixels(outW, outH,GL_RGBA, GL_FLOAT, result)
 
    def getPixels(self):    
        return self.pixels
        
    def setSource(self, outputGui):
        self.source = outputGui
        
    def isDone(self):
        return self.doneBack
    
    def getDepths(self):
        return self.depths

    def drawTable(self): 
        ''' 
        glEnableClientState(GL_VERTEX_ARRAY)
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[0])
        glVertexPointer(4, GL_FLOAT, 0, None)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[1])
        glDrawElements(GL_QUADS, len(edge), GL_UNSIGNED_INT, None)
        glDisableClientState(GL_VERTEX_ARRAY)
        '''
        return
        
    def drawDisk(self):
        glEnableClientState(GL_VERTEX_ARRAY)
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[2])
        glVertexPointer(4, GL_FLOAT, 0, None)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[3])
        glDrawElements(GL_TRIANGLES, len(self.diskEdge), GL_UNSIGNED_INT, None)        
        glDisableClientState(GL_VERTEX_ARRAY)
        
    def drawSphere(self):
        glEnableClientState(GL_VERTEX_ARRAY)
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[4])
        glVertexPointer(4, GL_FLOAT, 0, None)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[5])
        glDrawElements(GL_TRIANGLES, len(self.sphereEdge), GL_UNSIGNED_INT, None)     
        glDisableClientState(GL_VERTEX_ARRAY)
        
    def drawCube(self):
        glEnableClientState(GL_VERTEX_ARRAY)
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[6])
        glVertexPointer(4, GL_FLOAT, 0, None)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[7])
        glDrawElements(GL_TRIANGLES, len(self.cubeEdge), GL_UNSIGNED_INT, None)
        glDisableClientState(GL_VERTEX_ARRAY)       
    def setupObjects(self):
        global frame
        f=frame
        x = 40
        y = 5
        z = -80
        [self.diskVertex,self.diskEdge]=disk.vertexAndEdge(30+20*sin(f*6.2/512), x+20*sin(f*2.6/512), y+20*sin(f*2.7/512), z+20*sin(f*1.8/512), 16)
        
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[2])
        glBufferData(GL_ARRAY_BUFFER, self.diskVertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[3])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.diskEdge, GL_STATIC_DRAW)
        
        [self.sphereVertex,self.sphereEdge]=sphere.vertexAndEdge(10+10*sin(f*7.1/512), x+20*sin(f*2/512), y+20*sin(f*7.4/512), z+20*sin(f*6.3/512), 16)
        
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[4])
        glBufferData(GL_ARRAY_BUFFER, self.sphereVertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[5])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.sphereEdge, GL_STATIC_DRAW)
        
        [self.cubeVertex, self.cubeEdge] = cube.vertexAndEdge(x-30+20*sin(f*1.6/512), y-10+20*sin(f*2.6/512), z-40+20*sin(2.9/512), 10+10*sin(f*3.1/512), 10+10*sin(f*2.3/512), 10+10*sin(f*8.9/512))       
        
        glBindBuffer(GL_ARRAY_BUFFER, self.meshbuffers[6])
        glBufferData(GL_ARRAY_BUFFER, self.cubeVertex, GL_STATIC_DRAW)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.meshbuffers[7])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.cubeEdge, GL_STATIC_DRAW)
        
    def redraw(self):
        self.paintGL()
        
    def setDestination(self, outputGui):
        self.destination = outputGui
# Execute
if __name__ == "__main__":
    # Create the (single) Qt Application object, which starts everything up
    app = QApplication(sys.argv)
    useSupersampling = False    
    
    scaleHiDef = 1
    scaleLoDef = 1
    
    
    if(useSupersampling):
        scaleHiDef = 2 #higher -> bigger
        scaleLoDef = 1 #higher -> smaller
    #light point of view
    lightPov = MyGL(None, LIGHTPOV)
    lightPov.resize(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    lightPov.sizeLimit(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    lightPov.setWindowTitle("Light POV")
    lightPov.move(QPoint(0,0))
    lightPov.show()
    
    depthLight = MyGL(None, DEPTHLIGHT)
    depthLight.resize(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    depthLight.sizeLimit(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    depthLight.setWindowTitle("Depth Light")
    depthLight.setSource(lightPov)
    depthLight.move(QPoint(windowWidth,0))
    depthLight.show()
    
    cameraPov = MyGL(None, CAMERAPOV)
    cameraPov.resize(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    cameraPov.sizeLimit(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    cameraPov.setWindowTitle("Camera POV")
    cameraPov.setSource(lightPov)
    cameraPov.move(QPoint(0,windowHeight))
    cameraPov.show()
    
    depthCamera = MyGL(None, DEPTHCAMERA)
    depthCamera.resize(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    depthCamera.sizeLimit(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    depthCamera.setWindowTitle("Depth Camera")
    depthCamera.setSource(cameraPov)
    depthCamera.move(QPoint(windowWidth,windowHeight))
    depthCamera.show()    
    
    # Get our main window
    outputGui = MyGL(None, OUTPUT) 
    outputGui.resize(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    outputGui.sizeLimit(windowWidth*scaleHiDef, windowHeight*scaleHiDef)
    outputGui.setWindowTitle("Output")
    outputGui.move(QPoint(windowWidth*2,0))
    outputGui.setSource(cameraPov)
    outputGui.show()
    
    cameraPov.setDestination(outputGui)
    
    if(not useSupersampling):
        outputGui.setFocus()
    
    if(useSupersampling):
        # Supersampled window
        supersamplegui = MyGL(None, SUPERSAMPLE)
        supersamplegui.resize(windowWidth/scaleLoDef, windowHeight/scaleLoDef)
        supersamplegui.sizeLimit(windowWidth/scaleLoDef, windowHeight/scaleLoDef)
        supersamplegui.setSource(outputGui)
        supersamplegui.setWindowTitle("Supersample Output")
        supersamplegui.show()
        supersamplegui.setFocus()

    # Run it
    app.exec_()
    sys.exit()
